package controller

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gogf/gf/errors/gerror"
	"gitlab.local/DO-module/new-filemanage-module/src/constant"
	"gitlab.local/DO-module/new-filemanage-module/src/controller/errcode"
	//"gitlab.local/DO-module/new-filemanage-module/src/core/fileoperate"
	"gitlab.local/DO-module/new-filemanage-module/src/core/middleware"
	"gitlab.local/DO-module/new-filemanage-module/src/service/filesystem"
	"gitlab.local/DO-module/new-filemanage-module/src/service/filesystem/filefunc"
	"gitlab.local/DO-module/new-filemanage-module/src/service/folder"
	flog "gitlab.local/DO-module/new-filemanage-module/src/service/log"
	file_socket "gitlab.local/DO-module/new-filemanage-module/src/service/websocket"

	"gitlab.local/TerraMaster/tos-modules/fileoperate"
	//"gitlab.local/TerraMaster/tos-modules/middleware"
	"gitlab.local/golibrary/resp"
	"gitlab.local/golibrary/utils"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
)

type FileOpt struct {
	fs           *filesystem.FileSystem
	folders      *folder.Folder
	fOptGetter   fileoperate.Getter
	uploadStatus string //考虑到初始化默认值，""：没有初始化，"1":重命名,"2"：覆盖,"3"：跳过
}

func InitFileFuncRouter(engine *gin.Engine,
	checker middleware.AuthChecker,
	fOptGetter fileoperate.Getter,
	fs *filesystem.FileSystem,
	folders *folder.Folder) *FileOpt {

	fo := FileOpt{}
	fo.fs = fs
	fo.folders = folders
	fo.fOptGetter = fOptGetter
	fileManage := engine.Group("/fileManage")
	{
		fileManage.GET("/fileDownload", fo.handleFileDownload) //文件下载
	}

	fileManage = engine.Group("/fileManage", checker.LoginAuthed())
	{
		fileManage.POST("/folderRename", resp.WrapResp(fo.handleFolderRename)) //文件重命名
		fileManage.POST("/CreateFolder", resp.WrapResp(fo.handleCreateFolder)) //创建文件或文件夹
		fileManage.POST("/CheckQuota", resp.WrapResp(fo.handleCheckQuota))     //检查容量
		fileManage.POST("/moveFiles", resp.WrapResp(fo.handleMoveCopyFiles))   //移动或复制文件或文件夹
		fileManage.POST("/zipCompress", resp.WrapResp(fo.handleZipCompress))   //zip压缩文件
		fileManage.POST("/unZipCompress", resp.WrapResp(fo.handleUnCompress))  //解压文件
		fileManage.POST("/fileUpload", resp.WrapResp(fo.handleFileUpload))     //文件上传

		fileManage.PUT("/fileUpdate", resp.WrapResp(fo.handleFileUpdate))        //文件上传(文件编辑后保存)
		fileManage.DELETE("/delFolders", resp.WrapResp(fo.handleDelFolders))     //批量删除文件和文件夹
		fileManage.POST("/fileExist", resp.WrapResp(fo.handleFileExist))         //文件是否存在
		fileManage.DELETE("/clearRecycle", resp.WrapResp(fo.handleClearRecycle)) //回收站清空

		//后台任务
		fileManage.GET("/geBackgroundTaskLogs", resp.WrapResp(fo.handleGeBackgroundTaskLogs)) //获取后台任务日志
		fileManage.GET("/GetBackgroundTaskLog", resp.WrapResp(fo.handleGetBackgroundTaskLog)) //获取单条后台任务日志
		fileManage.POST("/stopBackgroundTask", resp.WrapResp(fo.handleStopBackgroundTask))    //停止后台任务
		fileManage.POST("/clearCompleteLog", resp.WrapResp(fo.handleStopAllBackgroundTask))   //停止全部后台任务

		//远程下载
		fileManage.POST("/remoteDownload", resp.WrapResp(fo.handleRemoteDownload))                         //远程下载
		fileManage.GET("/getRemoteDownloadList", resp.WrapResp(fo.handleGetRemoteDownloadList))            //获取远程下载日志
		fileManage.DELETE("/breakRemoteDownload", resp.WrapResp(fo.handleBreakRemoteDownload))             //清除单个远程下载任务
		fileManage.DELETE("/breakRemoteDownloadAll", resp.WrapResp(fo.handleBreakRemoteDownloadAll))       //清除全部远程下载任务
		fileManage.DELETE("/ClearCompleteLogs", resp.WrapResp(fo.handleClearCompleteLogs))                 //清除已完成的任务
		fileManage.POST("/PauseRemoteDownloadTask", resp.WrapResp(fo.handlePauseRemoteDownloadTask))       //暂停单个远程下载任务
		fileManage.POST("/PauseAllRemoteDownloadTask", resp.WrapResp(fo.handlePauseAllRemoteDownloadTask)) //暂停所有远程下载任务
		fileManage.POST("/RunRemoteDownloadTask", resp.WrapResp(fo.handleRunRemoteDownloadTask))           //运行远程下载任务
		fileManage.POST("/RunAllRemoteDownloadTask", resp.WrapResp(fo.handleRunAllRemoteDownloadTask))     //运行全部远程下载任务

	}
	webSocket := engine.Group("/fileManage")
	{
		webSocket.GET("/webSocket", fo.handleWebSocket) //websocket
	}

	return &fo
}

// handleWebSocket websocket
func (f *FileOpt) handleWebSocket(c *gin.Context) {
	file_socket.HandleWebSocket(c, f.fs.FileFunc.MethodType)
}

// handleFolderRename 文件重命名
func (f *FileOpt) handleFolderRename(c *gin.Context) (interface{}, error) {
	uname, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}
	var data struct {
		Path  string `json:"path"`   //文件路径
		RName string `json:"r_name"` //新名称
	}
	//解析json
	if e := c.BindJSON(&data); e != nil {
		flog.RecordedLog(flog.Err, uname, flog.HttpTag, "failed to rename the file procedure", c.ClientIP())
		return nil, e
	}

	if data.Path == "" || data.RName == "" {
		flog.RecordedLog(flog.Err, uname, flog.HttpTag, "failed to rename the file procedure", c.ClientIP())
		return nil, errors.New("parameter parsing failed")
	}

	//校验文件名称合法性
	if regexp.MustCompile(constant.FolderNameRule).MatchString(data.RName) {
		flog.RecordedLog(flog.Err, uname, flog.HttpTag, "failed to rename the file procedure", c.ClientIP())
		return nil, gerror.NewCode(errcode.NameContainsIllegalCharacters)
	}

	res, e := f.fOptGetter.FolderRenameFilter(data.Path, data.RName, uname, 1)
	if e != nil {
		flog.RecordedLog(flog.Err, uname, flog.HttpTag, "failed to rename the file procedure", c.ClientIP())
	} else {
		flog.RecordedLog(flog.Info, uname, flog.HttpTag, "the file was renamed successfully procedure", c.ClientIP())
		if res.FType != utils.Folder {
			//记入最近
			f.fs.FileNav.WriteRecently(uname, res.Path)
		}
	}
	return res, e
}

// handleCreateFolder 创建文件或文件夹
func (f *FileOpt) handleCreateFolder(c *gin.Context) (interface{}, error) {
	var data struct {
		Path   string `json:"path"`    //文件路径
		Type   int8   `json:"type"`    //1:文件，2:文件夹
		BackUp int8   `json:"back_up"` //是否备份 0:否； 1:是
	}

	uname, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}

	//解析json
	if e := c.BindJSON(&data); e != nil {
		flog.RecordedLog(flog.Err, uname, flog.HttpTag, "failed to create a file or folder procedure", c.ClientIP())
		return nil, e
	}

	if data.Path == "" {
		flog.RecordedLog(flog.Err, uname, flog.HttpTag, "failed to create a file or folder procedure", c.ClientIP())
		return nil, errors.New("parameter parsing failed")
	}

	//校验文件名称合法性
	if regexp.MustCompile(constant.FolderNameRule).MatchString(filepath.Base(data.Path)) {
		flog.RecordedLog(flog.Err, uname, flog.HttpTag, "failed to rename the file procedure", c.ClientIP())
		return nil, gerror.NewCode(errcode.NameContainsIllegalCharacters)
	}

	if utils.Exists(data.Path) {
		//0  重命名; 1  覆盖; 2  跳过
		conf, _ := f.fs.FileNav.GetRecentlyConf(uname)
		//如果是手机备份，直接返回文件信息
		if data.BackUp == 1 {
			return f.fOptGetter.GetFolder(data.Path)
		}
		switch conf.UploadFileOperation {
		case 0:
			i := 0
			for {
				i += 1
				dirName := fmt.Sprintf("%s(%d)", data.Path, i)
				if _, err := os.Stat(dirName); err != nil {
					data.Path = dirName
					break
				}
			}
		case 1:
			rmCmd := fmt.Sprintf(`rm -rf %s;`, data.Path)
			if _, err := utils.ShellExec(rmCmd); err != nil {
				return nil, gerror.NewCode(errcode.FailedToDelete)
			}
		default:
			return nil, nil
		}
	}

	res, e := f.fOptGetter.CreateFolderFilter(data.Path, data.Type, uname)
	if e != nil {
		flog.RecordedLog(flog.Err, uname, flog.HttpTag, "failed to create a file or folder procedure", c.ClientIP())
	} else {
		flog.RecordedLog(flog.Info, uname, flog.HttpTag, "succeeded in creating a file or folder procedure", c.ClientIP())
		if data.Type == 1 {
			//记入最近
			f.fs.FileNav.WriteRecently(uname, res.Path)
		}
	}

	return res, e
}

// handleCheckQuota 检查容量
func (f *FileOpt) handleCheckQuota(c *gin.Context) (interface{}, error) {
	var reqParam struct {
		Path string `json:"path"`
		Size int64  `json:"totalSize"`
	}
	if err := c.BindJSON(&reqParam); err != nil {
		return nil, err
	}

	username, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}
	if err := f.folders.VerifyQuota(reqParam.Size, username, reqParam.Path); err != nil {
		return false, gerror.NewCode(errcode.InsufficientHardDiskCapacity)
	}

	return true, nil
}

// handleFileUpload 分片上传文件
func (f *FileOpt) handleFileUpload(c *gin.Context) (interface{}, error) {
	uname, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}

	return f.fs.FileFunc.HandleFileUploadOld(c, uname)
}

// handleFileUpdate 文件上传(文件编辑后保存)
func (f *FileOpt) handleFileUpdate(c *gin.Context) (interface{}, error) {
	uname, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}
	//上传地址
	editPath := c.PostForm("path")
	//权限判断
	if !f.folders.Acl.IsWrite(editPath, uname) {
		return nil, gerror.NewCode(errcode.PermissionDenied, editPath)
	}
	file, err := c.FormFile("file")
	if err != nil {
		return nil, err
	}
	return f.folders.UpdateFile(editPath, file)
}

// handleDelFolders 批量删除文件和文件夹
func (f *FileOpt) handleDelFolders(c *gin.Context) (interface{}, error) {
	username, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}
	var data struct {
		Paths []string `json:"paths"`
	}
	if e := c.BindJSON(&data); e != nil {
		flog.RecordedLog(flog.Err, username, flog.HttpTag, "failed to delete a file", c.ClientIP())
		return false, e
	}
	if len(data.Paths) == 0 {
		flog.RecordedLog(flog.Err, username, flog.HttpTag, "failed to delete a file", c.ClientIP())
		return false, errors.New("request path error")
	}

	if e := f.fs.FileFunc.DelFolders(username, data.Paths...); e != nil {
		flog.RecordedLog(flog.Err, username, flog.HttpTag, "failed to delete a file", c.ClientIP())
		return false, e
	}
	flog.RecordedLog(flog.Info, username, flog.HttpTag, "deleting a file succeeded", c.ClientIP())
	return true, nil
}

// handleFileDownload 文件下载
func (f *FileOpt) handleFileDownload(c *gin.Context) {
	uname, err := middleware.GetUserName(c)
	if err != nil {
		c.String(http.StatusBadRequest, "failed to get username")
		return
	}
	arr, _ := c.GetQueryArray("paths")
	paths := make([]string, 0)
	for _, v := range arr {
		if v == "" {
			continue
		}
		paths = append(paths, v)
	}
	if len(paths) == 0 {
		flog.RecordedLog(flog.Err, uname, flog.HttpTag, "file download failure", c.ClientIP())
		c.String(http.StatusOK, "parameter parsing failed")
		return
	}
	if e := f.fs.FileFunc.FileDownload(uname, paths, c); e != nil {
		flog.RecordedLog(flog.Err, uname, flog.HttpTag, "file download failure", c.ClientIP())
		c.String(http.StatusInternalServerError, e.Error())
	} else {
		flog.RecordedLog(flog.Info, uname, flog.HttpTag, "file downloaded successfully", c.ClientIP())
	}
}

// handleBreakRemoteDownload 清除单个远程下载任务
func (f *FileOpt) handleBreakRemoteDownload(c *gin.Context) (interface{}, error) {
	taskId := c.Query("task_id")
	if taskId == "" {
		return false, errors.New("task_id is empty")
	}

	username, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}
	err = f.folders.BreakRemoteDownload(taskId, username)
	return err == nil, err
}

// handleBreakRemoteDownloadAll 清除全部远程下载任务
func (f *FileOpt) handleBreakRemoteDownloadAll(c *gin.Context) (interface{}, error) {
	username, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}
	err = f.folders.BreakRemoteDownloadAll(username)
	return err == nil, err
}

// handleClearCompleteLogs 清除已完成的任务
func (f *FileOpt) handleClearCompleteLogs(c *gin.Context) (interface{}, error) {
	username, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}
	err = f.folders.ClearCompleteLogs(username)
	return err == nil, err
}

// handlePauseRemoteDownloadTask 暂停远程下载任务
func (f *FileOpt) handlePauseRemoteDownloadTask(c *gin.Context) (interface{}, error) {
	var data struct {
		TaskId string `json:"task_id"`
	}
	if err := c.BindJSON(&data); err != nil {
		return false, err
	}

	if data.TaskId == "" {
		return false, errors.New("task_id is empty")
	}

	username, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}
	err = f.folders.PauseRemoteDownloadTask(data.TaskId, username)
	return err == nil, err
}

// handlePauseAllRemoteDownloadTask 暂停所有远程下载任务
func (f *FileOpt) handlePauseAllRemoteDownloadTask(c *gin.Context) (interface{}, error) {
	username, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}
	err = f.folders.PauseAllRemoteDownloadTask(username)
	return err == nil, err
}

// handleRunRemoteDownloadTask 运行远程下载任务
func (f *FileOpt) handleRunRemoteDownloadTask(c *gin.Context) (interface{}, error) {
	var data struct {
		TaskId string `json:"task_id"`
	}
	if err := c.BindJSON(&data); err != nil {
		return false, err
	}

	if data.TaskId == "" {
		return false, errors.New("task_id is empty")
	}

	username, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}
	err = f.folders.RunRemoteDownloadTask(data.TaskId, username)
	return err == nil, err
}

// handleRunAllRemoteDownloadTask 运行全部远程下载任务
func (f *FileOpt) handleRunAllRemoteDownloadTask(c *gin.Context) (interface{}, error) {
	username, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}
	err = f.folders.RunAllRemoteDownloadTask(username)
	return err == nil, err
}

// handleFileExist 文件是否存在
func (f *FileOpt) handleFileExist(c *gin.Context) (interface{}, error) {
	data := filefunc.FileData{}
	if err := c.BindJSON(&data); err != nil {
		return false, err
	}
	if data.Path == "" {
		return false, errors.New("path is empty")
	}
	return f.fs.FileFunc.FileExist(data), nil
}

// handleClearRecycle 清空回收站，判断权限
func (f *FileOpt) handleClearRecycle(c *gin.Context) (interface{}, error) {
	name := c.Query("name")
	uname, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}
	if name == "" {
		return false, errors.New("param error")
	}
	path := filepath.Join(name, "#recycle")

	if !f.folders.Acl.IsWrite(path, uname) || !f.folders.Acl.IsRead(path, uname) {
		return nil, gerror.NewCode(errcode.PermissionDenied, path)
	}
	if !f.folders.Acl.IsWrite(path, uname) || !f.folders.Acl.IsRead(path, uname) {
		return nil, gerror.NewCode(errcode.PermissionDenied, path)
	}

	_, _ = utils.ShellExec(fmt.Sprintf("rm -rf %s/* %s/.*", path, path))
	return true, nil
}

// handleZipCompress zip压缩
func (f *FileOpt) handleZipCompress(c *gin.Context) (interface{}, error) {
	uname, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}

	return f.fs.FileFunc.FileCompress(c, uname)
}

// handleUnCompress 解压
func (f *FileOpt) handleUnCompress(c *gin.Context) (interface{}, error) {
	uname, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}

	return f.fs.FileFunc.UnCompress(c, uname)
}

// handleMoveFiles 移动或复制文件或文件夹
func (f *FileOpt) handleMoveCopyFiles(c *gin.Context) (interface{}, error) {
	uname, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}

	return f.fs.FileFunc.MoveCopyFiles(c, uname)
}

// handleRemoteDownload 远程下载
func (f *FileOpt) handleRemoteDownload(c *gin.Context) (interface{}, error) {
	uname, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}

	return f.fs.FileFunc.PreHandleRemoteDownload(c, uname)
}

// handleGetRemoteDownloadList 获取远程下载日志
func (f *FileOpt) handleGetRemoteDownloadList(c *gin.Context) (interface{}, error) {
	username, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}
	return f.fs.FileFunc.HandleGetRemoteDownloadList(username)
}

// handleGeBackgroundTaskLogs 获取后台任务日志
func (f *FileOpt) handleGeBackgroundTaskLogs(c *gin.Context) (interface{}, error) {
	username, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}
	return f.fOptGetter.GetBackgroundTaskLogs(username)
}

// handleGetBackgroundTaskLog 获取单条后台任务日志
func (f *FileOpt) handleGetBackgroundTaskLog(c *gin.Context) (interface{}, error) {
	taskId := c.Query("task_id")
	if taskId == "" {
		return nil, errors.New("task_id is empty")
	}

	id, err := strconv.ParseInt(taskId, 10, 64)
	if err != nil {
		return nil, errors.New("task_id is error")
	}

	return f.fOptGetter.GetBackgroundTaskLog(id), nil
}

// handleStopBackgroundTask 停止后台任务
func (f *FileOpt) handleStopBackgroundTask(c *gin.Context) (interface{}, error) {
	var data []string
	if e := c.BindJSON(&data); e != nil {
		return false, e
	}
	err := f.fOptGetter.StopBackgroundTask(data)
	return err == nil, err
}

// handleStopAllBackgroundTask 停止全部后台任务
func (f *FileOpt) handleStopAllBackgroundTask(c *gin.Context) (interface{}, error) {
	username, err := middleware.GetUserName(c)
	if err != nil {
		return nil, err
	}
	err = f.fOptGetter.StopAllMvOrCp(username)
	return err == nil, err
}
